//
// Created by jiaxv on 2025/8/8.
//

#include "define.h"
#include "interface/ground.h"
#include "services/dashboard.h"

fsm_event_t gsg_fsm_events[] = {
    {"GSG_INITIAL", NULL, NULL},
    {"GSG_SAC_ALLOCING", NULL, NULL},
    {"GSG_CONNECTED", NULL, NULL},
    {"GSG_HO_OTHER", NULL, NULL},
    {"GSG_HO_CURRENT", NULL, NULL},
    {"GSG_EXIT", NULL, NULL},
};

static struct sm_state_s gsg_states[] = {
    {
        .data = "GSG_INITIAL",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "GSG_SAC_ALLOCING", &default_guard, NULL, &gsg_states[GSG_SAC_ALLOCING]},
            {EV_DEFAULT, (void *) "GSG_CONNECTED", &default_guard, NULL, &gsg_states[GSG_CONNECTED]},
        },
        .numTransitions = 2,
    },
    {
        .data = "GSG_SAC_ALLOCING",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "GSG_CONNECTED", &default_guard, NULL, &gsg_states[GSG_CONNECTED]},
            {EV_DEFAULT, (void *) "GSG_INITIAL", &default_guard, NULL, &gsg_states[GSG_INITIAL]},
        },
        .numTransitions = 2,
    },
    {
        .data = "GSG_CONNECTED",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "GSG_HO_OTHER", &default_guard, NULL, &gsg_states[GSG_HO_OTHER]},
            {EV_DEFAULT, (void *) "GSG_HO_CURRENT", &default_guard, NULL, &gsg_states[GSG_HO_CURRENT]},
            {EV_DEFAULT, (void *) "GSG_EXIT", &default_guard, NULL, &gsg_states[GSG_EXIT]},
        },
        .numTransitions = 3,
    },
    {
        .data = "GSG_HO_OTHER",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "GSG_CONNECTED", &default_guard, NULL, &gsg_states[GSG_CONNECTED]},
        },
        .numTransitions = 1,
    },
    {
        .data = "GSG_HO_CURRENT",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "GSG_CONNECTED", &default_guard, NULL, &gsg_states[GSG_CONNECTED]},
        },
        .numTransitions = 1,
    },
    {
        .data = "GSG_EXIT",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "GSG_INITIAL", &default_guard, NULL, &gsg_states[GSG_INITIAL]},
        },
        .numTransitions = 1,
    }
};

void init_gsg_fsm(sm_statemachine_t *sm) {
    stateM_init(sm, &gsg_states[GSG_INITIAL], NULL);
}

fsm_event_t amm_fsm_events[] = {
    {"AMM_INITIAL", NULL, NULL},
    {"AMM_AUTH", NULL, NULL},
    {"AMM_CONNECTING", NULL, NULL},
    {"AMM_CONNECTED", NULL, NULL},
    {"AMM_HO_PREPARE", NULL, NULL},
    {"AMM_HO_EXECUTE", NULL, NULL},
    {"AMM_EXIT", NULL, NULL},
};

static struct sm_state_s amm_states[] = {
    {
        .data = "AMM_INITIAL",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_AUTH", &default_guard, NULL, &amm_states[AMM_AUTH]},
        },
        .numTransitions = 1,
    },
    {
        .data = "AMM_AUTH",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_CONNECTING", &default_guard, NULL, &amm_states[AMM_CONNECTING]},
        },
        .numTransitions = 1,
    },
    {
        .data = "AMM_CONNECTING",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_CONNECTED", &default_guard, NULL, &amm_states[AMM_CONNECTED]},
        },
        .numTransitions = 1,
    },
    {
        .data = "AMM_CONNECTED",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_HO_PREPARE", &default_guard, NULL, &amm_states[AMM_HO_PREPARE]},
            {EV_DEFAULT, (void *) "AMM_EXIT", &default_guard, NULL, &amm_states[AMM_EXIT]},
        },
        .numTransitions = 2,
    },
    {
        .data = "AMM_HO_PREPARE",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_HO_EXECUTE", &default_guard, NULL, &amm_states[AMM_HO_EXECUTE]},
        },
        .numTransitions = 1,
    },
    {
        .data = "AMM_HO_EXECUTE",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_CONNECTED", &default_guard, NULL, &amm_states[AMM_CONNECTED]},
        },
        .numTransitions = 1,
    },
    {
        .data = "AMM_EXIT",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "AMM_INITIAL", &default_guard, NULL, &amm_states[AMM_INITIAL]},
        },
        .numTransitions = 1,
    }
};

void init_amm_fsm(sm_statemachine_t *sm) {
    stateM_init(sm, &amm_states[AMM_INITIAL], NULL);
}

fsm_event_t dbsm_fsm_events[] = {
    {"DBSM_INITIAL", NULL, NULL},
    {"DBSM_CONNECTING", NULL, NULL},
    {"DBSM_CONNECTED", NULL, NULL},
    {"DBSM_HO", NULL, NULL},
    {"DBSM_EXIT", NULL, NULL},
};

static struct sm_state_s dbsm_states[] = {
    {
        .data = "DBSM_INITIAL",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "DBSM_CONNECTING", &default_guard, NULL, &dbsm_states[DBSM_CONNECTING]},
        },
        .numTransitions = 1,
    },
    {
        .data = "DBSM_CONNECTING",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "DBSM_CONNECTED", &default_guard, NULL, &dbsm_states[DBSM_CONNECTED]},
        },
        .numTransitions = 1,
    },
    {
        .data = "DBSM_CONNECTED",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "DBSM_HO", &default_guard, NULL, &dbsm_states[DBSM_HO]},
            {EV_DEFAULT, (void *) "DBSM_EXIT", &default_guard, NULL, &dbsm_states[DBSM_EXIT]},
        },
        .numTransitions = 2,
    },
    {
        .data = "DBSM_HO",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) "DBSM_CONNECTED", &default_guard, NULL, &dbsm_states[DBSM_CONNECTED]},
        },
        .numTransitions = 1,
    },
    {
        .data = "DBSM_EXIT",
        .entryAction = &sm_default_entry_action,
        .exitAction = &sm_default_exit_action,
        .transitions = (sm_transition_t[]){
            {EV_DEFAULT, (void *) " DBSM_INITIAL", &default_guard, NULL, &dbsm_states[DBSM_INITIAL]},
        },
        .numTransitions = 1,
    }
};

void init_dbsm_fsm(sm_statemachine_t *sm) {
    stateM_init(sm, &dbsm_states[DBSM_INITIAL], NULL);
}

l_err default_cn_send_handler(net_element_t *net_ele, void *data, cn_format_desc_t *send_desc, element_propt_t *propt, interface_type_t intf_type) {

    if (!send_desc) {
        cn_log_error(net_ele->element_tag, intf_type, "No desc");
        return LD_ERR_NULL;
    }

    if (!propt) {
        cn_log_error(net_ele->element_tag, intf_type, "No propt");
        return LD_ERR_NULL;
    }
    meta_service_t *meta = propt->bc.opt->arg;

    buffer_t *to_send = gen_pdu( data, send_desc->f_desc, send_desc->tag);

    if (meta->ctx.send_handler(&propt->bc, to_send, NULL, NULL) != LD_OK) {
        cn_log_error(net_ele->element_tag, intf_type, "Send Message Failed!");
        return LD_ERR_INTERNAL;
    }

    if (is_dashboard) {
        handle_upload_cn_signalling_dashboard(&net_ele->dashboard_obj, net_ele->SAC, propt->peer_sac, intf_type,
                                              send_desc->type);
    }

    free_buffer(to_send);

    return LD_OK;
}

l_err default_cn_forward_handler(net_element_t *net_ele, buffer_t *buf, element_propt_t *propt, interface_type_t intf_type) {
    if (!propt) {
        cn_log_error(net_ele->element_tag, intf_type, "No propt");
        return LD_ERR_NULL;
    }
    meta_service_t *meta = propt->bc.opt->arg;

    if (meta->ctx.send_handler(&propt->bc, buf, NULL, NULL) != LD_OK) {
        cn_log_error(net_ele->element_tag, intf_type, "Send Message Failed!");
        return LD_ERR_INTERNAL;
    }

    if (is_dashboard) {
        handle_upload_cn_signalling_dashboard(&net_ele->dashboard_obj, net_ele->SAC, propt->peer_sac, intf_type,
                                              buf->ptr[0]);
    }

    return LD_OK;
}
